﻿// Copyright 2011 Jackson Hong
// This program is distributed under the terms of the GNU General Public License.
// 
// This file is part of FileRenameTool.
// 
// FileRenameTool is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// FileRenameTool is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with FileRenameTool.  If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;

namespace FileRenameTool
{
    internal sealed partial class FileRenameTool : Form
    {
        private static readonly List<FileInfo> _originalFiles = new List<FileInfo>() ;
        private static readonly List<String> _newFileName = new List<String>();
        private static Boolean _isLowerCase = true;
        private static Boolean _addLeadingZeros = true;
        private static DirectoryInfo _fileDirectory;

        public FileRenameTool()
        {
            InitializeComponent();

            Resize += new EventHandler(FileRenameToolResize);
            textBoxFileNamePattern.TextChanged += new EventHandler(TextBoxFileNamePatternTextChanged);
            numericStartValue.ValueChanged += new EventHandler(NumericStartValueValueChanged);
        }

        private void ButtonBrowseClick(object sender, EventArgs e)
        {
            if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    int index = 0;
                    textBoxFolderPath.Text = folderBrowserDialog.SelectedPath;
                    _fileDirectory = new DirectoryInfo(textBoxFolderPath.Text);
                    _originalFiles.Clear();
                    _newFileName.Clear();
                    listViewFiles.Items.Clear();

                    foreach (FileInfo fileInfo in _fileDirectory.GetFiles())
                    {
                        if ((fileInfo.Attributes & FileAttributes.Hidden) != FileAttributes.Hidden &&
                            (fileInfo.Attributes & FileAttributes.System) != FileAttributes.System)
                        {
                            _originalFiles.Add(fileInfo);
                        }
                    }

                    _originalFiles.Sort((fileInfo1, fileInfo2) => Comparer<DateTime>.Default.Compare(fileInfo1.LastWriteTime, fileInfo2.LastWriteTime));

                    foreach (FileInfo fileInfo in _originalFiles)
                    {
                        _newFileName.Add(fileInfo.Name.Replace(fileInfo.Extension, fileInfo.Extension.ToLower()));
                        ListViewItem listItem = new ListViewItem(fileInfo.Name);
                        listItem.SubItems.Add(_newFileName[index++]);
                        listViewFiles.Items.Add(listItem);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString(), "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }

                columnOriginalName.AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
                columnNewName.AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
            }
        }

        /// <summary>
        /// Update list view with new file names
        /// </summary>
        /// <param name="updateOriginalName">Whether to update the original file name column or not</param>
        private void UpdateListView(Boolean updateOriginalName)
        {
            _newFileName.Clear();

            int startValue = (int) numericStartValue.Value;
            int leadingZeros = _originalFiles.Count.ToString().Length;

            foreach (FileInfo fileInfo in _originalFiles)
            {
                int index = _originalFiles.IndexOf(fileInfo);

                if (updateOriginalName)
                {
                    listViewFiles.Items[index].SubItems[0].Text = fileInfo.Name;
                }

                _newFileName.Add(textBoxFileNamePattern.Text + (_addLeadingZeros ? startValue.ToString("D" + leadingZeros) : startValue.ToString()) + (_isLowerCase ? fileInfo.Extension.ToLower() : fileInfo.Extension.ToUpper()));
                listViewFiles.Items[index].SubItems[1].Text = _newFileName[index];
                startValue++;
            }
        }

        private void ChangeName()
        {
            UInt32 successfulRename = 0;

            foreach (FileInfo fileInfo in _originalFiles)
            {
                try
                {
                    if (fileInfo.Directory != null)
                    {
                        File.Move(fileInfo.FullName, Path.Combine(fileInfo.Directory.ToString(), _newFileName[_originalFiles.IndexOf(fileInfo)]));
                        successfulRename++;
                    }
                }
                catch (Exception e)
                {
                    if (!(e is IOException))
                    {
                        MessageBox.Show(e.ToString());
                        break;
                    }
                }
            }

            _fileDirectory = new DirectoryInfo(textBoxFolderPath.Text);
            _originalFiles.Clear();
            _newFileName.Clear();
            _originalFiles.AddRange(_fileDirectory.GetFiles());

            UpdateListView(true);

            MessageBox.Show(String.Format("{0}/{1} files renamed successfully.", successfulRename, _originalFiles.Count), "Result", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        #region Control Event Handlers
        /// <summary>
        /// Initially resize the column header width to fit the text of the column header
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FileRenameToolLoad(object sender, EventArgs e)
        {
            columnOriginalName.AutoResize(ColumnHeaderAutoResizeStyle.HeaderSize);
            columnNewName.AutoResize(ColumnHeaderAutoResizeStyle.HeaderSize);
        }

        /// <summary>
        /// Change the column header auto resize to accomodate the longest item in the list
        /// if the list is not empty
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FileRenameToolResize(object sender, EventArgs e)
        {
            if (listViewFiles.Items.Count != 0)
            {
                columnOriginalName.AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
                columnNewName.AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
            }
        }

        private void RadioButtonLowerCaseExtensionCheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonLowerCaseExtension.Checked)
            {
                _isLowerCase = true;
                UpdateListView(false);
            }
        }

        private void RadioButtonUpperCaseExtensionCheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonUpperCaseExtension.Checked)
            {
                _isLowerCase = false;
                UpdateListView(false);
            }
        }

        private void TextBoxFileNamePatternTextChanged(object sender, EventArgs e)
        {
            UpdateListView(false);
        }

        private void NumericStartValueValueChanged(object sender, EventArgs e)
        {
            UpdateListView(false);
        }

        private void ButtonRunClick(object sender, EventArgs e)
        {
            ChangeName();
        }

        private void CheckBoxLeadingZeroCheckedChanged(object sender, EventArgs e)
        {
            _addLeadingZeros = checkBoxLeadingZero.Checked;
            UpdateListView(false);
        }

        #endregion Control Event Handlers
    }
}
